//: annotations/InterfaceExtractorProcessor.java
// APT-based annotation processing.
// {Exec: apt -factory
// annotations.InterfaceExtractorProcessorFactory
// Multiplier.java -s ../annotations}
package annotations;
import com.sun.mirror.apt.*;
import com.sun.mirror.declaration.*;
import java.io.*;
import java.util.*;

public class InterfaceExtractorProcessor implements AnnotationProcessor {
  private final AnnotationProcessorEnvironment env;
  private ArrayList<MethodDeclaration> interfaceMethods = new ArrayList<MethodDeclaration>();
  public InterfaceExtractorProcessor(AnnotationProcessorEnvironment env) { this.env = env; }

  /**
   * 处理器 从env得到类型声明
   * 通过env可以知道apt正在处理的类的定义(所有的类型信息)
   * env也是获取类型信息的一个接口
   * 根据运行命令行 我猜evn是apt自动装备的，apt得到类文件地址，装备信息到env，
   * 这样便可以从env获取类型信息
   */
  public void process() {
    for(TypeDeclaration typeDecl : env.getSpecifiedTypeDeclarations()) {
      //类型声明获取注解类
      ExtractInterface annot = typeDecl.getAnnotation(ExtractInterface.class);
      if(annot == null)
        break;
      //类型声明获取方法声明类
      for(MethodDeclaration m : typeDecl.getMethods())
        if(m.getModifiers().contains(Modifier.PUBLIC) &&
                !(m.getModifiers().contains(Modifier.STATIC)))
          interfaceMethods.add(m);
      if(interfaceMethods.size() > 0) {
        try {
          //env获取过滤器，并创建文件${annot.value()}.java的输出流
          PrintWriter writer = env.getFiler().createSourceFile(annot.value());
          //通过println输出文件信息
          writer.println("package " +
            typeDecl.getPackage().getQualifiedName() +";");
          writer.println("public interface " +
            annot.value() + " {");
          for(MethodDeclaration m : interfaceMethods) {
            writer.print("  public ");
            writer.print(m.getReturnType() + " ");
            writer.print(m.getSimpleName() + " (");
            int i = 0;
            for(ParameterDeclaration parm : m.getParameters()) {
              writer.print(parm.getType() + " " +
                parm.getSimpleName());
              if(++i < m.getParameters().size())
                writer.print(", ");
            }
            writer.println(");");
          }
          writer.println("}");
          writer.close();
        } catch(IOException ioe) {
          throw new RuntimeException(ioe);
        }
      }
    }
  }
} ///:~
